home *** CD-ROM | disk | FTP | other *** search
- /* GRAPHIC LISP */
- /* Scritto nel 1991-94 da Zoia Andrea Michele */
- /* Via Pergola #1 Tirano (SO) Tel. 0342-704210 */
- /* file clos_clm.c */
-
- #include "clos.h"
-
- /* ---------------- TIPI DI DATI USATI DA METHOD_EVAL--------------------- */
- /* method -> (lambda1 lambda2 .... lambdan ) */
- /* lambda -> contiene una struttura dati con i seguenti campi: */
- /* UFUNC_TYPE=lista di tipi(vedi sotto) */
- /* UFUNC_PAR=lista dei nomi di parametri */
- /* UFUNC_SEX=lista di s-espressioni da valutare */
- /* UFUNC_KEY,UFUNC_AUX=UFUNC_OPT=liste associative (A-LIST) */
- /* contenenti i nomi delle variabili opzionali,ausiliarie e chiave*/
- /* ed i loro valori iniziali non ancora valutati. */
- /* UFUNC_REST=nome della variabile a cui assegnare il resto dei parametri */
- /* UFUNC_ENV=lista associativa contenente l'environment incapsulato all' */
- /* atto della definizione della lambda */
- /* NOTA: method_eval usa soltanto UFUNC_TYPE */
- /* tutti gli altri campi sono usati da Lambda_eval */
- /* */
- /* class instance->( (C0 C1 C2 ... Cn T) (fields of C0)...(fields of Cn) ) */
- /* lista di precedenze campi delle classi che appaiono */
- /* C0 e' la classe nella lista delle precedenze */
- /* istanziata (a parte T ) */
- /* Non sono usati da method-eval */
- /* Sono usati soltanto da accessor_eval*/
-
-
- /* METHOD_EVAL CONTIENE L'ALGORITMO DI SELEZIONE DEL METODO ESATTO */
- /* TRA TUTTI QUELLI DISPONIBILI.*/
- /* Un metodo e' una lista di nodi-lambda cioe' di nodi che contengono delle */
- /* funzioni utente. Tra i vari campi del nodo-lambda c'e' UFUNC_TYPE che */
- /* contiene una lista di nomi di classi o NIL */
- /* Corrispondentemente c'e' UFUNC_PAR che e' una lista dei nomi delle */
- /* variabili della lambda. Ad ogni nome di parametro in UFUNC_PAR corrisponde*/
- /* un tipo in UFUNC_TYPE . */
- /* Se il tipo e' un nome allora questo nome corrisponde */
- /* ad una definizione di classe e l'argomento deve essere un istanza di */
- /* quella classe o una istanza di una sua sottoclasse. */
- /* Se il tipo e' nil allora l'argomento puo' */
- /* essere di qualsiasi tipo */
-
- void method_eval(method,parlist,nout,genv,lenv,eval_flags)
- node method;
- node parlist;
- node_p *nout;
- node genv;
- node lenv;
- unsigned eval_flags;
- {
- node parl;
- node type_needed;
- node prec_list;
- node tmp;
- node mlist;
- node current_method;
- lsiz_t current_parameter;
- lsiz_t methods_number;
- int second_pass_needed;
- int class_matched;
-
-
- /* method e' la lista di tutte le funzioni che fanno capo da un metodo */
- /* parlist contiene una lista di tutti gli argomenti valutati */
- /* nout e' il puntatore alla struttura che conterra' il risultato della */
- /* funzione scelta */
- /* genv e' l'environment speciale dove ci sono le variabili definite */
- /* con DEFVAR */
- /* lenv e' 'environment locale */
- /* eval_flags sono dei flags da passare a lambda_eval assieme a genv e lenv */
-
- methods_number=listlen_func(method);
- /* methods_number contiene il numero delle funzioni che fanno capo */
- /* al metodo corrente */
-
- /************* prima passata della lista method ***********************/
- /* si escludono solo i metodi che non hanno la classe nella prec-list */
- /* del parametro cioe' i metodi inutilizzabili alla luce degli */
- /* argomenti attuali */
- /**********************************************************************/
-
- current_parameter=0;
- /* e' il contatore del' argomento in esame */
-
- /* si scorre tutta la parlist */
- parl=parlist;
- while(IS_CONS(parl)){
- tmp=CONSLEFT(parl);
- if(IS_VALUE(tmp)&&GET_VTYPE(tmp)==NT_CLASS){
- prec_list=CONSLEFT(CLASS_INSTANCE(tmp));
- }else{
- prec_list=NIL;
- }
- /* prec_list contiene la lista di precedenze della classe */
- /* argomento del metodo oppure NIL se l'argomento non e' una classe */
- /* NB: prec_list=lista di nomi di classi */
-
- /* si scorre la lista delle funzioni che fanno capo a questo metodo */
- mlist=method;
- while(IS_CONS(mlist)){
- current_method=CONSLEFT(mlist);
-
- if(IS_REM(current_method)){
- /* se il metodo corrente e' gia' stato escluso allora lo si salta */
- mlist=CONSRIGHT(mlist);
- continue;
- }
-
- type_needed=list_elt(UFUNC_TYPE(current_method),current_parameter);
- /* UFUNC_TYPE ritorna la lista dei tipi di parametri del metodo */
- /* e con list_elt si prende il tipo puntato da current_parameter */
- /* type_needed contiene il tipo del parametro voluto dalla funzione */
- /* NB: il tipo del parametro e' il nome della classe */
- /* se list_elt ritorna VOID vuol dire che la lista e' piu' corta */
- /* del previsto:allora si esclude la funzione corrente */
- if(type_needed==VOID){
- REM(current_method);
- methods_number--;
- mlist=CONSRIGHT(mlist);
- continue;
- }
- if(prec_list==NIL){
- /* l'argomento in esame non e' una classe */
- if(type_needed!=NIL){
- /* pero' la funzione richiede una classe */
- /* allora si esclude questo metodo */
- REM(current_method);
- methods_number--;
- }
- /* else */
- /* nemmeno la funzione vuole una classe allora va bene */
- }else{
- /* l'argomento in esame e' una classe */
- if(type_needed!=NIL){
- /* anche la funzione richiede una classe */
- /* si cerca se type_needed e' nella prec_list */
- tmp=prec_list;
- while(IS_CONS(tmp) && CONSLEFT(tmp)!=type_needed)
- tmp=CONSRIGHT(tmp);
-
- if(!IS_CONS(tmp)){
- /* type_needed non e' nella prec_list */
- /* si esclude questa funzione */
- REM(current_method);
- methods_number--;
- }
- }
- /* else */
- /* se l'argomento in esame e' una classe e la funzione richiede */
- /* un tipo generico di dato allora per ora si tiene buona la funzione */
- }/* else (prec_list==NIL) */
-
- /* si passa alla funzione successiva */
- mlist=CONSRIGHT(mlist);
- }/* while */
- /* si e' finito di scorrere la lista delle funzioni del metodo */
-
- /* si continua a sfoltire la method-list servendosi del */
- /* secondo parametro */
- parl=CONSRIGHT(parl);
- current_parameter++;
- }/* while */
-
- /* si controlla se non ci sono piu' funzioni */
- if(!methods_number)
- /* qui' si usa goto per evitare duplicazioni di codice */
- goto UnmatchError;
-
- /* si controlla se e' rimasta una sola funzione */
- if(methods_number==1)
- /* qui' si usa goto per evitare duplicazioni di codice */
- goto MethodFound;
-
- /* Arrivati fin qui' si sono escluse tutte quelle funzioni che non */
- /* possono essere applicate. */
- /* Quelle che rimangono devono essere sfoltite basandosi sulla lista */
- /* delle prececdenze delle classi. */
- /* NB: ognuna delle funzioni rimanenti potrebbe essere applicata */
- /* con i parametri attuali :lo scopo della seconda passata e' proprio */
- /* quello di trovare il metodo migliore compatibilmente con i parametri */
- /* attuali. */
-
-
- /************* seconda passata della lista method**********************/
- /* si escludono via via tutte le funzioni che possono essere */
- /* applicate a classi di minor precedenza rispetto ad altre */
- /* NOTA: la seconda passata puo' richiedere a sua volta 2 passate */
- /* per essere completata */
- /* ed e' a questa seconda ''sottopassata,, alla quale si */
- /* riferisce il flag second_pass_needed */
- /**********************************************************************/
-
- current_parameter=0;
-
- /* si prova a scorrere tutta la parlist */
- parl=parlist;
- while(IS_CONS(parl)){
- tmp=CONSLEFT(parl);
- if(IS_VALUE(tmp)&&GET_VTYPE(tmp)==NT_CLASS){
- prec_list=CONSLEFT(CLASS_INSTANCE(tmp));
- }else{
- prec_list=NIL;
- }
- /* prec_list contiene la lista di precedenze della classe */
- /* argomento del metodo oppure NIL se l'argomento non e' una classe */
- /* NB: precl=lista di nomi di classi */
-
- /* prima passata della lista method */
- /* si inizializzano i 2 flags */
- class_matched=FALSE;
- second_pass_needed=FALSE;
-
- mlist=method;
- while(IS_CONS(mlist)){
-
- current_method=CONSLEFT(mlist);
- /* current_method=metodo corrente */
-
- if(IS_REM(current_method)){
- /* se il metodo corrente e' gia' stato escluso allora lo si salta */
- mlist=CONSRIGHT(mlist);
- continue;
- }
-
- type_needed=list_elt(UFUNC_TYPE(current_method),current_parameter);
- /* NOTA: ora list_elt tova sicuramente l'elemento current_parameter */
- /* nella lista UFUNC_TYPE(method) dato che nella passata precedente */
- /* sono state escluse tutte le funzioni che non avevano un numero */
- /* sufficiente di parametri */
-
- /* se prec_list==NIL allora la prima passata ha gia' provveduto ad */
- /* escludere la funzione nel caso che type_needed!=NIL o a tenerla */
- /* buona se type_needed==NIL */
-
- if(prec_list!=NIL){
- if(type_needed==NIL){
- /* il parametro formale e' una classe e il metodo richede un */
- /* tipo generico di dato : allora si marca il metodo solo se non ne */
- /* sono stati trovati altri che potrebbero andar bene. */
- /* comunque c'e' bisogno di una seconda passata della lista */
- /* dei metodi in modo da poter escludere questo metodo */
- /* se se ne troveranno altri piu' corretti */
- if(class_matched){
- REM(current_method);
- methods_number--;
- }else{
- second_pass_needed=TRUE;
- }
- }else{
- /* il parametro formale e' una classe ed anche il metodo richiede */
- /* una classe : allora si vede se type_needed (del metodo) e' in */
- /* prec_list (precedenze del parametro formale) prima o in */
- /* coincidenza della prima classe marcata in prec_list */
- /* se non lo si trova in prec_list allora si esclude il metodo */
- /* se lo si trova allora si vede se e' in concomitanza della classe */
- /* marcata (cioe' quella con precedenza piu' elevata incontrata */
- /* finora): se e' cosi' si tiene buono il metodo */
- /* se invece typel si trova prima della prima classe marcata */
- /* allora oltre a tenere buono il metodo bisogna fare una seconda */
- /* passata per escludere i metodi che si riferivano ad una classe */
- /* con minore precedenza */
-
- /* cerca type_needed in prec_list e si ferma alla fine di precl */
- /* o al primo elemento marcato */
- tmp=prec_list;
- while( IS_CONS(tmp) && !IS_REM(CONSLEFT(tmp)) ){
- if(CONSLEFT(tmp)==type_needed)break;
- tmp=CONSRIGHT(tmp);
- }
- if(IS_CONS(tmp)){
- /* il while precedente si e' interrotto perche' si e' */
- /* verificata l'uguaglianza e/o si e' trovato un nodo REM */
- if(CONSLEFT(tmp)==type_needed){
- /* e' stata trovata una classe che va bene */
- if(!IS_REM(CONSLEFT(tmp))){
- /* la classe non era marcata :la si marca */
- /* e si richiede una seconda passata solo se il flag */
- /* class matched e' TRUE */
- /* cioe' se e' gia' stato trovato un metodo riferito ad una */
- /* classe con precedenza minore allora fai una */
- /* seconda passata per eliminarlo */
- REM(CONSLEFT(tmp));
- if(class_matched){
- second_pass_needed=TRUE;
- }
- class_matched=TRUE;
- }
- /* else */
- /* era gia' marcata non c'e' bisogno di una seconda */
- /* passata e non c'e' bisogno nemmeno di settare il flag */
- /* class_matched perche' dato che qualcosa e' gia' stato */
- /* marcato allora si sara' provveduto a settare questo flag */
- /* insomma qui' non si fa nulla ed il metodo va bene */
- /* ---- */
- }else{
- /* non e' stata trovata la classe: si esclude il metodo */
- REM(current_method);
- methods_number--;
- }
- }else{
- /* non e' stata trovata la classe: si esclude il metodo */
- REM(current_method);
- methods_number--;
- }
- }/* else (type_needed==NIL) */
- }/* if (prec_list==NIL) */
-
- /* si passa al prossimo metodo */
- mlist=CONSRIGHT(mlist);
- }/* while prima passata */
-
- if(second_pass_needed){
-
- /* seconda passata della lista method */
- mlist=method;
- while(IS_CONS(mlist)){
-
- current_method=CONSLEFT(mlist);
-
- if(IS_REM(current_method)){
- /* se il metodo corrente e' gia' stato escluso allora lo si salta */
- mlist=CONSRIGHT(mlist);
- continue;
- }
-
- type_needed=list_elt(UFUNC_TYPE(current_method),current_parameter);
- /* NOTA: ora list_elt tova sicuramente l'elemento current_parameter */
- /* nella lista UFUNC_TYPE(method) dato che nella passata precedente */
- /* sono state escluse tutte le funzioni che non avevano un numero */
- /* sufficiente di parametri */
-
- /* se prec_list==NIL in entrambi i casi di typel */
- /* non si fa nulla dato che la prima */
- /* passata qui' ha gia' fatto tutto il possibile */
- if(prec_list!=NIL){
- if(type_needed==NIL){
- /* il parametro formale e' una classe e il metodo richede un */
- /* tipo generico di dato : allora si marca il metodo solo se */
- /* non ne sono stati trovati altri (nella passata precedente) che */
- /* potrebbero andar bene. */
- if(class_matched){
- REM(current_method);
- methods_number--;
- }
- }else{
- /* il parametro formale e' una classe ed anche il metodo richiede */
- /* una classe : allora si vede se type_needed (del metodo) e' in */
- /* prec_list (precedenze del parametro formale) in coincidenza */
- /* della prima classe marcata in precl */
- /* NB: se trova una classe questa DEVE essere in coincidenza */
- /* con la prima classe marcata , fatto garantito dalla */
- /* passata precedente.*/
- /* se non lo si trova in precl allora si esclude il metodo */
-
- /* cerca typel in precl e si ferma alla fine di precl */
- /* o al primo elemento marcato */
- tmp=prec_list;
- while( IS_CONS(tmp) && !IS_REM(CONSLEFT(tmp)) ){
- if(CONSLEFT(tmp)==type_needed)break;
- tmp=CONSRIGHT(tmp);
- }
- if(IS_CONS(tmp)){
- /* il while precedente si e' interrotto perche' si e' */
- /* verificata l'uguaglianza e/o si e' trovato un nodo REM */
- if(CONSLEFT(tmp)!=type_needed){
- /* non e' stata trovata la classe: si esclude il metodo */
- REM(current_method);
- methods_number--;
- }
- }else{
- /* qui' la classe non va bene */
- REM(current_method);
- methods_number--;
- }
- }/* else (type_needed==NIL) */
- }/* if (prec_list!=NIL) */
-
- /* si passa al prossimo metodo */
- mlist=CONSRIGHT(mlist);
- }/* while seconda passata */
- }/* if (second_pass_needed) */
-
- /* ora si tolgono tutte le marcature da prec_list */
- tmp=prec_list;
- while(IS_CONS(tmp)){
- UNREM(CONSLEFT(tmp));
- tmp=CONSRIGHT(tmp);
- }
-
- /* si continua a sfoltire */
- /* la method-list servendosi del prossimo parametro */
- current_parameter++;
- parl=CONSRIGHT(parl);
- } /* while (IS_CONS(parl)) */
-
- if(methods_number==1){
- /* nella method-list e' rimasto un solo elemento ed e' proprio */
- /* quello giusto (e non marcato) !!! */
- /* lo si cerca e lo si valuta con lambda-eval */
- /* intanto si smarca anche tutta la method_list */
-
- MethodFound: /* qui' va a finire un goto precedente */
- tmp=method;
- while(IS_CONS(tmp)){
- if(IS_REM(CONSLEFT(tmp)))
- UNREM(CONSLEFT(tmp));
- else
- type_needed=CONSLEFT(tmp);
- tmp=CONSRIGHT(tmp);
- }
- lambda_eval(type_needed,parlist,nout,genv,lenv,eval_flags);
- return;
- }
-
- /* si controlla il contatore methods_number */
- if(!methods_number){
- /* errore sono rimasti zero metodi */
- /* si smarca tutta la method-list */
- UnmatchError: /* qui' va a finire un goto precedente */
- tmp=method;
- while(IS_CONS(tmp)){
- UNREM(CONSLEFT(tmp));
- tmp=CONSRIGHT(tmp);
- }
- error(E_UNMATCHEDMETHOD,ERR_MERROR|ERR_TBLVL|ERR_PVOID,NULL);
- }
-
- /* se si arriva fin qui' significa che piu' di un metodo va bene */
- /* allora si genera l'errore di ambiguita' */
-
- /* si smarca tutta la method-list */
- tmp=method;
- while(IS_CONS(tmp)){
- UNREM(CONSLEFT(tmp));
- tmp=CONSRIGHT(tmp);
- }
- error(E_AMBIGUOUSMETHOD,ERR_MERROR|ERR_TBLVL|ERR_PNINT,&methods_number);
- }
-
-
-
-
-
-
- void accessor_eval(access,nin,nout,genv,lenv)
- node access;
- node nin;
- node_p *nout;
- node genv;
- node lenv;
- {
- lsiz_t counter=0;
- node supers;
-
- if(IS_CONS(nin)){
- eval(CONSLEFT(nin),nout,genv,lenv,EVAL_NORM);
- nin=calc_pointer(nout);
- if(IS_VALUE(nin)&&GET_VTYPE(nin)==NT_CLASS){
- /* nin e' una classe */
- nin=CLASS_INSTANCE(nin);
- /* si vede se ACCESSOR_NAME si trova nella prec-list della classe */
- supers=CONSLEFT(nin);
- nin=CONSRIGHT(nin);
- while(IS_CONS(supers)){
- if(CONSLEFT(supers)==ACCESSOR_NAME(access)){
- /* posizionati sulla lista della classe scelta */
- while(counter--)nin=CONSRIGHT(nin);
- nin=CONSLEFT(nin);
- counter=ACCESSOR_FIELD(access);
- /* posizionati sull campo scelto della classe */
- while(--counter)nin=CONSRIGHT(nin);
- nout->node=nin;
- nout->type=P_CONSLEFT;
- return;
- }
- counter++;
- supers=CONSRIGHT(supers);
- }
- error(E_UNMATCHCLASS,ERR_MERROR|ERR_PNODE|ERR_TBLVL,&ACCESSOR_NAME(access));
- }
- error(E_BADARGS,ERR_MERROR|ERR_PNODE|ERR_TBLVL,&nin);
- }
- error(E_FEWARGS,ERR_MERROR|ERR_PNODE|ERR_TBLVL,&nin);
- }
-
-